home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2010 April / PCWorld0410.iso / hity wydania / Ubuntu 9.10 PL / karmelkowy-koliberek-9.10-netbook-remix-PL.iso / casper / filesystem.squashfs / usr / share / pyshared / Onboard / KeyboardSVG.py < prev    next >
Text File  |  2009-10-01  |  13KB  |  327 lines

  1. ### Logging ###
  2. import logging
  3. _logger = logging.getLogger("KeyboardSVG")
  4. ###############
  5.  
  6. from gettext import gettext as _
  7. from xml.dom import minidom
  8. import os
  9. import re
  10. import string
  11. import sys
  12.  
  13. from Onboard             import Exceptions
  14. from Onboard             import KeyCommon
  15. from Onboard.KeyGtk      import LineKey, RectKey
  16. from Onboard.Keyboard    import Keyboard
  17. from Onboard.KeyboardGTK import KeyboardGTK
  18. from Onboard.Pane        import Pane
  19. from Onboard.utils       import hexstring_to_float, modifiers, matmult
  20.  
  21. ### Config Singleton ###
  22. from Onboard.Config import Config
  23. config = Config()
  24. ########################
  25.  
  26. class KeyboardSVG(config.kbd_render_mixin, Keyboard):
  27.     """
  28.     Keyboard loaded from an SVG file.
  29.     """
  30.  
  31.     def __init__(self, filename):
  32.         config.kbd_render_mixin.__init__(self)
  33.         Keyboard.__init__(self)
  34.         self.load_layout(filename)
  35.         
  36.     def load_pane_svg(self, pane_xml, pane_svg):
  37.         keys = {}
  38.  
  39.         try:
  40.             pane_size = (
  41.                 float(pane_svg.attributes['width'].value.replace("px", "")),
  42.                 float(pane_svg.attributes['height'].value.replace("px", "")))
  43.             
  44.         except ValueError:
  45.             raise Exceptions.SVGSyntaxError(_("Units for canvas height and"
  46.                 " width must currently be px (pixels)."))
  47.  
  48.         #find background of pane
  49.         pane_background = [0.0,0.0,0.0,0.0]
  50.  
  51.         if pane_xml.hasAttribute("backgroundRed"):
  52.             pane_background[0] = pane_xml.attributes["backgroundRed"].value
  53.         if pane_xml.hasAttribute("backgroundGreen"):
  54.             pane_background[1] = pane_xml.attributes["backgroundGreen"].value
  55.         if pane_xml.hasAttribute("backgroundBlue"):
  56.             pane_background[2] = pane_xml.attributes["backgroundBlue"].value
  57.         if pane_xml.hasAttribute("backgroundAlpha"):
  58.             pane_background[3] = pane_xml.attributes["backgroundAlpha"].value
  59.  
  60.         #find label color of pane
  61.         pane_label_rgba = [0.0,0.0,0.0,1.0]
  62.  
  63.         if pane_xml.hasAttribute("labelRed"):
  64.             pane_label_rgba[0] = float(pane_xml.attributes["labelRed"].value)
  65.         if pane_xml.hasAttribute("labelGreen"):
  66.             pane_label_rgba[1] = float(pane_xml.attributes["labelGreen"].value)
  67.         if pane_xml.hasAttribute("labelBlue"):
  68.             pane_label_rgba[2] = float(pane_xml.attributes["labelBlue"].value)
  69.         if pane_xml.hasAttribute("labelAlpha"):
  70.             pane_label_rgba[3] = float(pane_xml.attributes["labelAlpha"].value)
  71.  
  72.         #scanning
  73.         columns = []
  74.         
  75.         self.load_keys_geometry(pane_svg, keys)
  76.         key_groups = self.load_keys(pane_xml, keys, pane_label_rgba)
  77.  
  78.         try:
  79.             for column_xml in pane_xml.getElementsByTagName("column"):
  80.                 column = []
  81.                 columns.append(column)
  82.                 for scanKey in column_xml.getElementsByTagName("scankey"):
  83.                     column.append(keys[scanKey.attributes["id"].value])
  84.         except KeyError, (exception):
  85.             raise Exceptions.LayoutFileError(
  86.                 _("%s appears in scanning definition only") % (str(exception)))
  87.         
  88.         return Pane(pane_xml.attributes["id"].value, key_groups,
  89.             columns, pane_size, pane_background)
  90.  
  91.  
  92.     def load_layout(self, layout_data_file):
  93.         kbfolder = os.path.dirname(layout_data_file)
  94.         panes = []
  95.  
  96.         f = open(layout_data_file)
  97.         try:
  98.             langdoc = minidom.parse(f).documentElement
  99.             try:    
  100.                 for pane_config in langdoc.getElementsByTagName("pane"):
  101.                     pane_svg_filename = os.path.join(kbfolder,
  102.                         pane_config.attributes["filename"].value)
  103.                     try:
  104.                         with open(pane_svg_filename) as svg_file:
  105.                             pane_svg = minidom.parse(svg_file).documentElement
  106.                         try:
  107.                             panes.append(
  108.                                 self.load_pane_svg(pane_config, pane_svg))
  109.                         finally:
  110.                             pane_svg.unlink()
  111.  
  112.                     except Exception, (exception):
  113.                         raise Exceptions.LayoutFileError(_("Error loading ")
  114.                             + pane_svg_filename, chained_exception = exception)
  115.             finally:
  116.                 langdoc.unlink()
  117.         finally:
  118.             f.close()
  119.         
  120.         
  121.         basePane = panes[0]
  122.         otherPanes = panes[1:]
  123.  
  124.         self.set_basePane(basePane)
  125.  
  126.         for pane in otherPanes:
  127.             self.add_pane(pane)
  128.  
  129.     def load_keys_geometry(self, svgdoc, keys):
  130.         for rect in svgdoc.getElementsByTagName("rect"): 
  131.             id = rect.attributes["id"].value
  132.             
  133.             styleString = rect.attributes["style"].value
  134.             result = re.search("(fill:#\d?\D?\d?\D?\d?\D?\d?\D?\d?\D?\d?\D?;)", 
  135.                 styleString).groups()[0]
  136.     
  137.             rgba = [hexstring_to_float(result[6:8])/255,
  138.             hexstring_to_float(result[8:10])/255,
  139.             hexstring_to_float(result[10:12])/255,
  140.             1]#not bothered for now 
  141.  
  142.             keys[id] = RectKey(id,
  143.                 (float(rect.attributes['x'].value),
  144.                  float(rect.attributes['y'].value)),
  145.                 (float(rect.attributes['width'].value),
  146.                  float(rect.attributes['height'].value)),
  147.                 rgba)
  148.         
  149.             # TODO fix LineKeys
  150.             """
  151.             for path in svgdoc.getElementsByTagName("path"):
  152.                 id = path.attributes["id"].value
  153.                 keys[id] = self.parse_path(path, pane)
  154.             """                     
  155.  
  156.     def load_keys(self, doc, keys, label_rgba):
  157.         groups = {}
  158.         for key_xml in doc.getElementsByTagName("key"):  
  159.             name = key_xml.attributes["id"].value
  160.             if name in keys:
  161.                 key = keys[name]
  162.                 if key_xml.hasAttribute("char"):
  163.                     key.action = key_xml.attributes["char"].value
  164.                     key.action_type = KeyCommon.CHAR_ACTION
  165.                 elif key_xml.hasAttribute("keysym"):
  166.                     value = key_xml.attributes["keysym"].value
  167.                     key.action_type = KeyCommon.KEYSYM_ACTION
  168.                     if value[1] == "x":#Deals for when keysym is hex
  169.                         key.action = string.atoi(value,16)
  170.                     else:
  171.                         key.action = string.atoi(value,10)
  172.                 elif key_xml.hasAttribute("keypress_name"):
  173.                     key.action = key_xml.attributes["keypress_name"].value
  174.                     key.action_type = KeyCommon.KEYPRESS_NAME_ACTION
  175.                 elif key_xml.hasAttribute("modifier"):
  176.                     try:
  177.                         key.action = modifiers[
  178.                                     key_xml.attributes["modifier"].value]
  179.                     except KeyError, (strerror):
  180.                         raise Exception("Unrecognised modifier %s in" \
  181.                             "definition of %s" (strerror, name))
  182.                     key.action_type = KeyCommon.MODIFIER_ACTION
  183.                         
  184.                 elif key_xml.hasAttribute("macro"):
  185.                     key.action = key_xml.attributes["macro"].value
  186.                     key.action_type = KeyCommon.MACRO_ACTION
  187.                 elif key_xml.hasAttribute("script"):
  188.                     key.action = key_xml.attributes["script"].value
  189.                     key.action_type = KeyCommon.SCRIPT_ACTION
  190.                 elif key_xml.hasAttribute("keycode"):
  191.                     key.action = string.atoi(
  192.                         key_xml.attributes["keycode"].value)
  193.                     key.action_type = KeyCommon.KEYCODE_ACTION
  194.                 else:
  195.                     raise Exceptions.LayoutFileError(name
  196.                         + " key does not have an action defined")
  197.  
  198.                 labels = ["","","","",""]
  199.                 #if label specified search for modified labels.
  200.                 if key_xml.hasAttribute("label"):
  201.                     labels[0] = key_xml.attributes["label"].value
  202.                     if key_xml.hasAttribute("cap_label"):
  203.                         labels[1] = key_xml.attributes["cap_label"].value
  204.                     if key_xml.hasAttribute("shift_label"):
  205.                         labels[2] = key_xml.attributes["shift_label"].value
  206.                     if key_xml.hasAttribute("altgr_label"):
  207.                         labels[3] = key_xml.attributes["altgr_label"].value
  208.                     if key_xml.hasAttribute("altgrNshift_label"):
  209.                         labels[4] = \
  210.                             key_xml.attributes["altgrNshift_label"].value   
  211.                 # If key is a macro (snippet) generate label from number.
  212.                 elif key.action_type == KeyCommon.MACRO_ACTION:
  213.                     labels[0] = "%s\n%s" % (_("Snippet"), key.action)
  214.                 # Get labels from keyboard.
  215.                 else:
  216.                     if key.action_type == KeyCommon.KEYCODE_ACTION:
  217.                         labDic = self.vk.labels_from_keycode(key.action)
  218.                         labels = (labDic[0],labDic[2],labDic[1],
  219.                                                     labDic[3],labDic[4])
  220.  
  221.                 # Translate labels - Gettext behaves oddly when translating
  222.                 # empty strings
  223.                 key.labels = [ lab and _(lab) or None for lab in labels ]
  224.  
  225.                 # assign label color - default label color is pane default
  226.                 key.label_rgba = label_rgba 
  227.  
  228.                 if key_xml.hasAttribute("font_offset_x"):
  229.                     offset_x = \
  230.                         float(key_xml.attributes["font_offset_x"].value)
  231.                 else:
  232.                     offset_x = config.DEFAULT_LABEL_OFFSET[0]
  233.                 
  234.                 if key_xml.hasAttribute("font_offset_y"):
  235.                     offset_x = \
  236.                         float(key_xml.attributes["font_offset_y"].value)
  237.                 else:
  238.                     offset_y = config.DEFAULT_LABEL_OFFSET[1]
  239.                 key.label_offset = (offset_x, offset_y)
  240.                 
  241.                 sticky = key_xml.attributes["sticky"].value.lower()
  242.                 if sticky:
  243.                     if sticky == "true":
  244.                         key.sticky = True
  245.                     elif sticky == "false":
  246.                         key.sticky = False
  247.                     else:
  248.                         raise Exception( "'sticky' attribute had an" 
  249.                             "invalid value: %s when parsing key %s" 
  250.                             % (sticky, name))
  251.                 else:
  252.                     key.sticky = False
  253.  
  254.                 if key_xml.hasAttribute("group"):
  255.                     group = key_xml.attributes["group"].value
  256.                 else:
  257.                     group = "_default"
  258.                 if not groups.has_key(group): groups[group] = []
  259.                 groups[group].append(key)
  260.         return groups            
  261.  
  262.     def parse_path(self, path, pane):
  263.         id = path.attributes["id"].value
  264.         styleString = path.attributes["style"].value
  265.         result = re.search("(fill:#\d?\D?\d?\D?\d?\D?\d?\D?\d?\D?\d?\D?;)", styleString).groups()[0]
  266.  
  267.         rgba = (hexstring_to_float(result[6:8])/255,
  268.         hexstring_to_float(result[8:10])/255,
  269.         hexstring_to_float(result[10:12])/255,
  270.         1)#not bothered for now
  271.  
  272.         dList = path.attributes["d"].value.split(" ")
  273.         dList = dList[1:-2] #trim unwanted M, Z
  274.         coordList = []
  275.  
  276.         transformMatrix = None
  277.         if path.hasAttribute("transform"):
  278.             transform = path.attributes["transform"].value
  279.             if transform.startswith("matrix"):
  280.                 #Convert strings to floats
  281.                 transformCoords = map(float,transform[7:-1].split(","))
  282.  
  283.                 transformMatrix = (
  284.                     (transformCoords[0],transformCoords[2],transformCoords[4]),
  285.                     (transformCoords[1],transformCoords[3],transformCoords[5]),
  286.                     (0, 0, 1))
  287.             elif transform.startswith("translate"):
  288.                 transformCoords = map(float,transform[10:-1].split(","))
  289.  
  290.                 transformMatrix = (
  291.                     (1.0,0.0,transformCoords[0]),
  292.                     (0.0,1.0,transformCoords[1]),
  293.                     (0.0,0.0,1.0)
  294.                 )
  295.             else:
  296.                 print "Warning: Unhandled transform " + transform
  297.  
  298.         xTotal = 0.0
  299.         yTotal = 0.0
  300.         numCoords = 0
  301.         for d in dList:
  302.             l = d.split(",")
  303.             if len(l) == 1:
  304.                 #A letter
  305.                 coordList.append(l)
  306.             else:
  307.                 #A coord
  308.                 numCoords = numCoords +1
  309.  
  310.                 l = map(float,l)
  311.  
  312.                 if transformMatrix:
  313.                     l = matmult(transformMatrix, l+[1])[:-1]
  314.  
  315.                 xTotal = xTotal + l[0]
  316.                 yTotal = yTotal + l[1]
  317.  
  318.                 coordList.append(l[0])
  319.                 coordList.append(l[1])
  320.  
  321.         #Point at which we want the label drawn
  322.         fontCoord = (xTotal/numCoords, yTotal/numCoords)
  323.  
  324.         return LineKey(pane, coordList, fontCoord, rgba)
  325.  
  326.  
  327.